const connection = require("../../config/mysql.js");
const bcrypt = require("bcryptjs");
const jwtUtil = require("../utils/permission/jwtutil");
const { _validateCharacterData } = require("./assistance.js");
/**
 * 用户控制器：处理注册、登录等逻辑
 */
class UserController {
    /**
     * 用户注册
     * 支持使用邮箱或手机号注册
     * 请求体示例：
     * @ "username": "testuser",
     * @ "email": "user@example.com",     // 可选
     * @ "phone": "13812345678",          // 可选
     * @ "password": "123456"
     */
    static async register(ctx) {
        const { username, email, phone, password } = ctx.request.body;

        // 1. 参数校验
        if (!username || !password) {
            ctx.status = 400;
            ctx.body = {
                code: 400,
                msg: "用户名和密码不能为空",
            };
            return;
        }

        if (!email && !phone) {
            ctx.status = 400;
            ctx.body = {
                code: 400,
                msg: "请提供邮箱或手机号",
            };
            return;
        }

        if (password.length < 6) {
            ctx.status = 400;
            ctx.body = {
                code: 400,
                msg: "密码长度不能小于6位",
            };
            return;
        }

        // 2. 校验邮箱或手机号是否已被注册
        let existingUser = null;
        let query = "";
        let params = [];

        if (email) {
            query = "SELECT id FROM accounts WHERE email = ?";
            params = [email];
        } else if (phone) {
            query = "SELECT id FROM accounts WHERE phone = ?";
            params = [phone];
        }

        try {
            const [rows] = await connection.execute(query, params);
            if (rows.length > 0) {
                ctx.status = 409;
                ctx.body = {
                    code: 409,
                    msg: email ? "该邮箱已被注册" : "该手机号已被注册",
                };
                return;
            }

            // 3. 加密密码
            const salt = await bcrypt.genSalt(10);
            const passwordHash = await bcrypt.hash(password, salt);

            // 4. 插入新用户
            const insertQuery = `
        INSERT INTO accounts 
        (username, email, phone, password_hash, nickname, created_at, updated_at) 
        VALUES (?, ?, ?, ?, ?, NOW(), NOW())
      `;
            const nickname = username; // 默认昵称等于用户名
            const insertParams = [username, email || null, phone || null, passwordHash, nickname];

            const [result] = await connection.execute(insertQuery, insertParams);

            const userId = result.insertId;

            // 5. 生成 JWT Token
            const token = jwtUtil.encrypt({
                id: userId,
                username: username,
                type: 10, // 默认普通用户
            });

            // 6. 返回成功响应（不含密码）
            ctx.status = 201;
            ctx.body = {
                code: 201,
                msg: "注册成功",
                data: {
                    id: userId,
                    username,
                    email,
                    phone,
                    nickname,
                    token,
                },
            };
        } catch (error) {
            console.error("注册错误:", error);
            ctx.status = 500;
            ctx.body = {
                code: 500,
                msg: "服务器内部错误",
            };
        }
    }

    /**
     * 用户登录
     * 支持邮箱或手机号 + 密码登录
     * 请求体示例：
     * @ "account": "user@example.com",  // 邮箱或手机号
     * @ "password": "123456"
     */
    static async login(ctx) {
        const { account, password } = ctx.request.body;

        // 1. 参数校验
        if (!account || !password) {
            ctx.status = 400;
            ctx.body = {
                code: 400,
                msg: "账号（邮箱/手机号）和密码不能为空",
            };
            return;
        }

        try {
            // 2. 判断是邮箱还是手机号
            const isEmail = account.includes("@");
            const isPhone = /^\d{11}$/.test(account);

            if (!isEmail && !isPhone) {
                ctx.status = 400;
                ctx.body = {
                    code: 400,
                    msg: "请输入有效的邮箱或手机号",
                };
                return;
            }

            // 3. 查询用户
            const query = isEmail
                ? "SELECT * FROM accounts WHERE email = ? AND status = 'active'"
                : "SELECT * FROM accounts WHERE phone = ? AND status = 'active'";

            const [rows] = await connection.execute(query, [account]);

            if (rows.length === 0) {
                ctx.status = 404;
                ctx.body = {
                    code: 404,
                    msg: "用户不存在或已被禁用",
                };
                return;
            }

            const user = rows[0];

            // 4. 校验密码
            const isValid = await bcrypt.compare(password, user.password_hash);
            if (!isValid) {
                ctx.status = 401;
                ctx.body = {
                    code: 401,
                    msg: "密码错误",
                };
                return;
            }

            // 5. 更新最后登录时间和IP
            const ip = ctx.request.ip.replace(/^::ffff:/, ""); // 处理IPv6转IPv4
            await connection.execute(
                "UPDATE accounts SET last_login_at = NOW(), last_login_ip = ? WHERE id = ?",
                [ip, user.id]
            );

            // 6. 生成 Token
            const token = jwtUtil.encrypt({
                id: user.id,
                username: user.username,
                type: user.user_type,
            });

            // 7. 返回用户信息（敏感字段过滤）
            const { password_hash, salt, ...safeUser } = user;

            ctx.body = {
                code: 200,
                msg: "登录成功",
                data: {
                    ...safeUser,
                    token,
                },
            };
        } catch (error) {
            console.error("登录错误:", error);
            ctx.status = 500;
            ctx.body = {
                code: 500,
                msg: "服务器内部错误",
            };
        }
    }
    /**
     * 获取玩家全部角色列表
     */
    static async getCharacters(ctx) {
        const userId = ctx.state.user?.id;
        if (!userId) {
            ctx.status = 401;
            ctx.body = {
                code: 401,
                msg: "请先登录",
            };
            return;
        }
        try {
            const [rows] = await connection.execute(
                "SELECT * FROM characters WHERE user_id = ?",
                [userId]
            );

            ctx.body = {
                code: 200,
                msg: "角色列表获取成功",
                data: rows,
            }
        } catch (error) {
            console.error("获取角色列表失败:", error);
            ctx.status = 500;
            ctx.body = {
                code: 500,
                msg: "服务器内部错误",
            };
        }
    }
    /**
     * 创建角色
     * POST /api/user/createCharacter
     * 请求体示例：
     * {
     *   "name": "阿尔萨斯",
     *   "gender": "male",         // male / female / other
     *   "job_class_id": 1         // 必须是 level=1 的基础职业 ID
     * }
     */
    static async createCharacter(ctx) {
        const { name, gender = 'other', job_class_id } = ctx.request.body;

        // 1. 验证是否登录（从 JWT 获取 user_id）
        const userId = ctx.state.user?.id;
        if (!userId) {
            ctx.status = 401;
            ctx.body = {
                code: 401,
                msg: "请先登录",
            };
            return;
        }

        // 2. 参数校验
        if (!name || !job_class_id) {
            ctx.status = 400;
            ctx.body = {
                code: 400,
                msg: "角色名和职业不能为空",
            };
            return;
        }

        if (name.length < 2 || name.length > 12) {
            ctx.status = 400;
            ctx.body = {
                code: 400,
                msg: "角色名长度应为2-12个字符",
            };
            return;
        }

        if (!['male', 'female', 'other'].includes(gender)) {
            ctx.status = 400;
            ctx.body = {
                code: 400,
                msg: "性别参数不合法",
            };
            return;
        }

        try {
            // 3. 验证职业是否存在且为基础职业（level = 1）
            const [jobRows] = await connection.execute(
                `SELECT 
         id, name, job_type,
         base_hp, base_mp, base_attack, base_defense, base_speed, base_critical_rate
       FROM job_classes 
       WHERE id = ? AND level = 1 AND is_active = TRUE`,
                [job_class_id]
            );

            if (jobRows.length === 0) {
                ctx.status = 400;
                ctx.body = {
                    code: 400,
                    msg: "所选职业无效或不可用",
                };
                return;
            }

            const job = jobRows[0];

            // 4. 检查该用户是否已创建角色
            const [existingChar] = await connection.execute(
                "SELECT id FROM characters WHERE user_id = ?",
                [userId]
            );

            if (existingChar.length > 0) {
                ctx.status = 400;
                ctx.body = {
                    code: 400,
                    msg: "每个用户仅限创建一个角色",
                };
                return;
            }

            // 5. 分配基础属性（根据职业倾向）
            const baseStrength = job.job_type === 'warrior' ? 12 : job.job_type === 'mage' ? 6 : 10;
            const baseIntelligence = job.job_type === 'mage' ? 12 : job.job_type === 'warrior' ? 6 : 8;
            const baseDexterity = job.job_type === 'rogue' ? 12 : 7;
            const baseVitality = job.job_type === 'warrior' ? 10 : job.job_type === 'mage' ? 6 : 8;

            // 6. ✅ 安全读取职业模板中的数值（强制转为浮点数）
            const base_hp = parseFloat(job.base_hp);
            const base_mp = parseFloat(job.base_mp);
            const base_attack = parseFloat(job.base_attack);
            const base_defense = parseFloat(job.base_defense);
            const base_speed = parseFloat(job.base_speed);
            const base_critical_rate = parseFloat(job.base_critical_rate);

            // 提供默认值防止 NaN
            const hp = isNaN(base_hp) ? 100 : parseFloat(base_hp.toFixed(2));
            const mp = isNaN(base_mp) ? 50 : parseFloat(base_mp.toFixed(2));
            const attack = parseFloat((base_attack + baseStrength * 1.5).toFixed(2));
            const defense = parseFloat((base_defense + baseVitality * 1.2).toFixed(2));
            const speed = parseFloat((base_speed + baseDexterity * 0.5).toFixed(2));
            const critical_rate = parseFloat((base_critical_rate + baseDexterity * 0.1).toFixed(2));

            // 7. 当前状态值
            const current_hp = hp;
            const current_mp = mp;
            const current_stamina = 80;

            // 8. 插入角色的 SQL（字段与 ? 严格一一对应）
            const insertQuery = `
      INSERT INTO characters (
        user_id, name, gender, job_class_id,
        level, exp, max_exp,
        strength, intelligence, dexterity, vitality,
        base_hp, base_mp, base_stamina,
        attack, defense, speed, critical_rate,
        current_hp, current_mp, current_stamina,
        created_at, updated_at
      ) VALUES (?, ?, ?, ?, 
                1, 0, 100, 
                ?, ?, ?, ?, 
                ?, ?, 80, 
                ?, ?, ?, ?, 
                ?, ?, ?, 
                NOW(), NOW())
    `;

            // 9. 参数顺序必须与 SQL 中的 ? 一一对应（共 16 个 ?）
            const params = [
                userId, name, gender, job_class_id,                    // 4
                baseStrength, baseIntelligence, baseDexterity, baseVitality, // 4
                hp, mp,                                               // 2
                attack, defense, speed, critical_rate,                // 4
                current_hp, current_mp, current_stamina               // 2
            ];

            // 🔍 调试用：打印参数和类型（上线可注释）
            // console.log("创建角色参数:", params);
            // console.log("参数类型:", params.map(p => typeof p));

            // 10. 执行插入
            const [result] = await connection.execute(insertQuery, params);
            const characterId = result.insertId;

            // 11. 返回成功响应
            ctx.body = {
                code: 200,
                msg: "角色创建成功",
                data: {
                    id: characterId,
                    name,
                    gender,
                    job_class_id,
                    job_name: job.name,
                    level: 1,
                    hp,
                    mp,
                    attack,
                    defense,
                    speed,
                    critical_rate,
                    created_at: new Date().toISOString().slice(0, 19).replace('T', ' ')
                },
            };

        } catch (error) {
            console.error("创建角色失败:", error);

            // 特殊处理 MySQL 字段错误（便于定位）
            if (error.code === 'ER_TRUNCATED_WRONG_VALUE_FOR_FIELD') {
                ctx.status = 400;
                ctx.body = {
                    code: 400,
                    msg: `角色属性值超出范围或格式错误：${error.sqlMessage}`,
                };
                return;
            }

            // 通用错误
            ctx.status = 500;
            ctx.body = {
                code: 500,
                msg: "服务器内部错误，请稍后重试",
            };
        }
    }

    /**
     * 选择角色（返回角色完整信息 + 职业模板，用于客户端/服务端属性校准）
     */
    static async selectCharacter(ctx) {
        const { characterId } = ctx.request.body;
        const userId = ctx.state.user?.id;

        // 1. 登录校验
        if (!userId) {
            ctx.status = 401;
            ctx.body = { code: 401, msg: "请先登录" };
            return;
        }

        // 2. 参数校验
        if (!characterId) {
            ctx.status = 400;
            ctx.body = { code: 400, msg: "角色ID不能为空" };
            return;
        }

        const cid = parseInt(characterId, 10);
        if (isNaN(cid) || cid <= 0) {
            ctx.status = 400;
            ctx.body = { code: 400, msg: "无效的角色ID" };
            return;
        }

        let conn;
        try {
            // 获取连接
            conn = await connection.getConnection();
            await conn.beginTransaction();

            // 3. 查询角色信息（显式字段，避免 SELECT *）
            const [charRows] = await conn.execute(
                `SELECT 
                id, user_id, name, gender, job_class_id,
                level, exp, max_exp,
                strength, intelligence, dexterity, vitality,
                base_hp, base_mp, base_stamina,
                attack, defense, speed, critical_rate,
                magic_attack, magic_defense,
                current_hp, current_mp, current_stamina,
                created_at, updated_at, status
             FROM characters 
             WHERE id = ? AND user_id = ?`,
                [cid, userId]
            );

            if (charRows.length === 0) {
                await conn.rollback();
                ctx.status = 404;
                ctx.body = { code: 404, msg: "角色不存在或无权限访问" };
                return;
            }

            const character = charRows[0];

            // 4. 查询职业信息
            const [jobRows] = await conn.execute(
                `SELECT 
                id, name, job_type,
                base_hp, base_mp, base_attack, base_defense,
                base_magic_attack, base_magic_defense, base_speed, base_critical_rate,
                growth_hp, growth_attack, growth_defense, growth_speed
             FROM job_classes 
             WHERE id = ? AND is_active = TRUE`,
                [character.job_class_id]
            );

            if (jobRows.length === 0) {
                await conn.rollback();
                ctx.status = 400;
                ctx.body = { code: 400, msg: "职业数据异常，请联系管理员" };
                return;
            }

            const job = jobRows[0];

            // 5. 校验并修复角色属性
            const validation = await _validateCharacterData(character, job);
            if (!validation.isLegal) {
                // 只更新需要修正的字段
                await conn.execute(
                    `UPDATE characters SET 
                    base_hp = ?, base_mp = ?,
                    attack = ?, defense = ?,
                    magic_attack = ?, magic_defense = ?,
                    speed = ?, critical_rate = ?,
                    updated_at = NOW()
                    WHERE id = ?`,
                    [
                        validation.data.base_hp,
                        validation.data.base_mp,
                        validation.data.attack,
                        validation.data.defense,
                        validation.data.magic_attack,
                        validation.data.magic_defense,
                        validation.data.speed,
                        validation.data.critical_rate,
                        cid
                    ]
                );
                // 更新本地数据
                Object.assign(character, validation.data);
            }

            // 6. 更新用户状态
            await conn.execute(
                "UPDATE accounts SET last_login_at = NOW(), status = 'active' WHERE id = ?",
                [userId]
            );

            // 7. 设置其他角色为离线状态
            await conn.execute(
                "UPDATE characters SET status = 'offline' WHERE user_id = ? AND id != ?",
                [userId, cid]
            );

            // 8. 再次查询最新角色数据（确保一致性）
            const [finalCharRows] = await conn.execute(
                "SELECT * FROM characters WHERE id = ? AND user_id = ?", [cid, userId]
            );

            await conn.commit();

            // 9. 返回响应
            ctx.body = {
                code: 200,
                msg: "角色选择成功，数据已加载"+validation.isLegal?"":"并已修正非法属性",
                data: {
                    character: finalCharRows[0],
                    job
                }
            };

        } catch (error) {
            if (conn) {
                await conn.rollback().catch(console.error);
            }

            console.error("选择角色失败:", error);

            ctx.status = 500;
            ctx.body = {
                code: 500,
                msg: "服务器内部错误，请稍后重试"
            };
        } finally {
            if (conn) conn.release();
        }
    }
}

module.exports = UserController;